package com.prj.ufdm.demo.tutorial.thread;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * ReadWriteLock : 读写锁，分为读锁和写锁，多个读锁不互斥，读锁与写锁互斥，这是由jvm自己控制的
  *  我们只要上好相应的锁即可。如果你的代码只读数据，可以很多人同时读，但不能同时写，那就上读锁；如果你的代码修改数据，只能有一个人在写，且不能同时读取，那就上写锁。）
 * 
  *   读写锁的机制：
 * "读-读" 不互斥
 * "读-写" 互斥
 * "写-写" 互斥
 * 
 */
public class TestReadWriteLock {

	public static void main(String[] args) throws Exception {
		
		TestReadWriteLockDemo rw = new TestReadWriteLockDemo();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 10; i++) {
					new Thread(new Runnable() {
						@Override
						public void run() {
							rw.write((int)(Math.random() * 101));
						}
					},"Write-Thread-"+i).start();
				}
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				for (int j = 0; j < 10; j++) {
					new Thread(new Runnable() {
						@Override
						public void run() {
							rw.read();
						}
					},"Read-Thread-"+j).start();
				}
			}
		}).start();
	}

}

class TestReadWriteLockDemo {
	
	private int number = 0;
	
	private ReadWriteLock lock = new ReentrantReadWriteLock();
	private Lock readLock = lock.readLock();
	private Lock writeLock = lock.writeLock();
	
	//读
	public void read(){
		readLock.lock(); //上锁
		try{
			System.out.println(Thread.currentThread().getName() + " start: " + number + "，获取读锁的时候，读线程可以进来");
			Thread.sleep(1000);
			System.out.println(Thread.currentThread().getName() + " end: " + number + "，获取读锁的时候，读线程可以进来");
		}
		catch(Exception er) {
			er.printStackTrace();
		}
		finally{
			readLock.unlock();
		}
	}
	
	//写
	public void write(int number) {
		writeLock.lock();
		try{
			System.out.println(Thread.currentThread().getName() + " start: " + number + "，写锁的时候，读写线程不可以进来");
			Thread.sleep(2000);
			System.out.println(Thread.currentThread().getName() + " end: " + number + "，写锁的时候，读写线程不可以进来");
			this.number = number;
		}
		catch(Exception er) {
			er.printStackTrace();
		}
		finally{
			writeLock.unlock();
		}
	}
}